package cn.datawin.service;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import cn.datawin.bean.Form;
import cn.datawin.bean.page.ReqData;
import cn.datawin.bean.page.RespData;
import cn.datawin.util.DbUtil;
import cn.datawin.util.JDBCUtil;
import cn.datawin.util.MD5;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;


@Service
public class TaskService extends BaseService{
	@Resource
	RuleService ruleService;
	@Resource
	RuleBaseService ruleBaseService;
	@Resource
	ClientService clientService;
	
	public void insertTask(String task, String rules) {
		List<Map<String, Object>> tasks = (List<Map<String, Object>>) deserialize(task);
		List<List<Map<String, Object>>> _rules = (List<List<Map<String, Object>>>) deserialize(rules);
		for(int i=0;i<tasks.size();i++){
			Map<String, Object> map = tasks.get(i);
			//TODO  remove v只留 _id String
			List<DBObject> dbObjects=remove(_rules.get(i));
			map.put("rules",dbObjects);   
			/**
			 * 插入检测
			 */
			if("DataProcessor".equals(map.get("processor")) 
					&& hasUrl((String)map.get("url"))) continue;
			
			this.insert("task", map);
		}
	}
	
	public List<DBObject> tract(List<Map<String, Object>> list) {
		List<DBObject> dbObjects=new ArrayList<DBObject>();
		for (Map<String, Object> map : list) {
			BasicDBObject dbObject=new BasicDBObject();
			for (String key : map.keySet()) {
				dbObject.put(key, map.get(key));
				dbObjects.add(dbObject);
			}
		}
		return dbObjects;
	}
	
	public List<DBObject> remove(List<Map<String, Object>> list) {
		List<DBObject> dbObjects = new ArrayList<DBObject>();
		for (Map<String, Object> map : list) {
			BasicDBObject dbObject=new BasicDBObject();
			dbObject.put("rid", map.get("rid").toString());
			dbObjects.add(dbObject);
			if(map.containsKey("children")){
				dbObject.put("children", remove((List<Map<String, Object>>)map.get("children")));
			}
		}
		return dbObjects;
	}
	
	public void insertData(String task) {
		Map<String, Object> map =(Map<String, Object>)deserialize(task);
		String col=map.get("col").toString();
		map.remove("col");
		Date date=new Date(Long.parseLong(map.get("date").toString()));
		map.put("date", date);
		DbUtil.getcoll(col).insert(new BasicDBObject(map));
	}
	
	public String insertTask(DBObject task) {
			String col="task";
			task.removeField("_id");
			return this.save(col, task);
	}
	
	public void updateState(String taskid,String state) {
			String col="task";
			DBObject query = new BasicDBObject();
			query.put("_id", new ObjectId(taskid));
			DBObject o=new BasicDBObject("state", state);
			
			this.updateSingle(col, query, o);
	}
	
	public void comptask(String taskid) {
		String col="task";
		DBObject query = new BasicDBObject();
		query.put("_id", new ObjectId(taskid));
		DBObject o=new BasicDBObject("state", "2");
		this.updateSingle(col, query, o);
	}
	
	public void failtask(String taskid) {
		String col="task";
		DBObject query = new BasicDBObject();
		query.put("_id", new ObjectId(taskid));
		DBObject o=new BasicDBObject("state", "3");
		this.updateSingle(col, query, o);
	}
	
	/**
	 * 所有的渠道 平均分配数量
	 * @param workbeach
	 * @param state
	 * @param num
	 * @return
	 */
	List<DBObject>  eachworkbeach(String workbeach, String state, int num){
		List<DBObject> eachlist= new ArrayList<DBObject>();
		List<String> ll = (List<String>) this.distinct("task", "workbeach", new BasicDBObject("root", true));
		DBObject query = new BasicDBObject();
		query.put("state", state);
		for(String w : ll){
			query.put("workbeach", w);
			List<DBObject> task = this.findList("task", query, null, 0, num);
			for(DBObject dbo: task){
				BasicDBList client = (BasicDBList)dbo.get("client");
				if(client != null &&client.contains(workbeach)){
					String _state = "1";
					eachlist.add(dbo);
					String taskid = dbo.get("_id").toString();
					this.updateState(taskid, _state);
				}
			}
		}
		return eachlist;
	}
	
	/**
	 *  select id, href from url where id=? limit 100 
	 * @param url
	 * @return
	 */
	public boolean hasUrl(String url){
		long id = MD5.md5_long(url.trim());
		Object obj = null;
		try {
			obj = JDBCUtil.QueryObject("select 1 from url where id = ?", id);
			if(obj !=null){
				return true;
			}
			JDBCUtil.insert("insert into url(id, href) values (?,?)", id, url);
			return false;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public String findTask(String workbeach,String state, int num){
		synchronized (this) {
			clientService.poll(workbeach);
			List<DBObject> task = eachworkbeach(workbeach, state, num);
			for (int i = 0; i < task.size(); i++) {
				DBObject dbo = task.get(i);
				String taskid = dbo.get("_id").toString();
				if (dbo.get("root")!= null &&(Boolean)dbo.get("root")) {
					DBObject rulequery = new BasicDBObject();
					rulequery.put("taskid", (taskid));
					rulequery.put("pid", "0");
					List<DBObject> rules = this.findList("rule", rulequery, new BasicDBObject("pid",1));
					for (int j = 0; j < rules.size(); j++) {
						DBObject ruleBase = ruleBaseService.findRuleBase(rules.get(j).get("rid").toString());
						DBObject rule = rules.get(j);
						rule.putAll(ruleBase);
					}
					getchild(rules);
					dbo.put("rules", rules);
				}else{
					//TODO 根据 _id children 查询到 rulebase 层次关系一样
					List<DBObject> rules=(List<DBObject>) dbo.get("rules");
					getchild1(rules);
					dbo.put("rules", rules);
				}
				
			}
//			System.out.println(":::::::::"+ serialize(task));
			return serialize(task);
		}
	}

	private DBObject getRule(String ruleid) {
		DBObject rulequery = new BasicDBObject();
		rulequery.put("_id", new ObjectId(ruleid));
		DBObject rule = this.findOne("rulebase", rulequery);
		return rule;
	}
	
	
	//找出uid对应的主任务id
	public List<DBObject> getkeywordid(String uid){
			BasicDBObject query = new BasicDBObject();
			query.put("uid", uid);
			List<DBObject> list = this.findList("task", query);
			return list;
	}
	
	public int getkeywordtasks(List<DBObject> dbObjects){
			//0未抓取完       1抓取完成       2不存在用户任务
			if(dbObjects.size()==0) return 2;
			boolean flag=true;
			for (DBObject dbObject : dbObjects) {
				if(!dbObject.get("state").toString().equals("2")){
					flag=false;
					break;
				}
				BasicDBObject query = new BasicDBObject();
				BasicDBObject cond1=new BasicDBObject();
				cond1.put("taskid", dbObject.get("_id").toString());
				cond1.put("state", "0");
				BasicDBObject cond2=new BasicDBObject();
				cond2.put("taskid", dbObject.get("_id").toString());
				cond2.put("state", "1");
				BasicDBList conds=new BasicDBList();  
			    conds.add(cond1);  
			    conds.add(cond2);  
			    query.put("$or", conds); 
				List<DBObject> list = this.findList("task", query);
				if(list.size()>0){
					flag=false;
					break;
				}
			}
			if(flag){
				return 1;
			}
			return 0;
	}
	
	
	public String getkeywords(String uid){
			List<DBObject> list=getkeywordid(uid);
			int s=getkeywordtasks(list);
			return s+"";
	}
	
	public void deleteTask(String id){
			String col="task";
			Map<String, Object> query = new HashMap<String, Object>();
			if(!StringUtils.hasLength(id))return;
			String[] ids = id.split(",");
			for(String i : ids){
				query.put("_id", new ObjectId(i));
				this.delete(col, query);
				this.delete("rule",new BasicDBObject("taskid",i));
			}
	}
	
	public void deletemidTask(){
			String col="task";
			Map<String, Object> query = new HashMap<String, Object>();
			query.put("root", false);
			query.put("state", "2");
			this.delete(col, query);
	}
	
	/**
	 * 只重置状态为3 DataProcessor 的task
		不删除删除子任务 删除子任务方式使用 手动判断的方式进行
	 */
	public void modifyTaskState(){
		BasicDBObject query = new BasicDBObject();
		query.put("state","3");
		query.put("processor", "DataProcessor");
		super.updateMultiSingle("task", query, new BasicDBObject("state","0"));
	}
	
	//状态为1的task重置为0
	public void resetTaskState(){
		String col="task";
		BasicDBList list = new BasicDBList();
		list.add("1");
		list.add("3");
		BasicDBObject query = new BasicDBObject();
		query.put("state",new BasicDBObject("$in", list));
		List<DBObject> dbObjects= this.findList(col, query);
		for (DBObject dbObject : dbObjects) {
			String dbid=dbObject.get("_id").toString();
			updateState(dbid, "0");
			deletechTask(dbid);
		}
	}
	
	
	public void deletechTask(String id){
		String col="task";
		Map<String, Object> query = new HashMap<String, Object>();
		if(!StringUtils.hasLength(id))return;
		query.put("taskid", id);
		this.delete(col, query);
	}
	
	public void deletemidData(){
		Set<String> colls=DbUtil.getcolls();
		for (String str : colls) {  
		      if(str.startsWith("b_") || str.startsWith("c_") ){
		    	  DBCollection coll= DbUtil.getcoll(str);
		    	  coll.remove(new BasicDBObject("state", "1"));
		      }
		}  
    }
	
	public Object getalltask(Form form,ReqData reqData){
		RespData<List<DBObject>> res=makeRes(form, reqData);
		return res;
	}
	
	public RespData<List<DBObject>> makeRes(Form form,ReqData reqData){
		RespData<List<DBObject>> respData = new RespData<List<DBObject>>();
		BasicDBObject query = new BasicDBObject("root", true);
		if(StringUtils.hasLength(form.getType()) ){
			query.remove("root");
			BasicDBList dblist =  new BasicDBList();
			dblist.add("1");
			dblist.add("3");
			query.append("state", new BasicDBObject("$in", dblist));
		}
		
		//获取条件
		
		if(StringUtils.hasLength(form.getKey())){
			Pattern pattern = Pattern.compile("^.*" + form.getKey()+ ".*$", Pattern.CASE_INSENSITIVE);
			BasicDBObject q1 = new BasicDBObject();
			q1.append("note", pattern);
			BasicDBObject q2 = new BasicDBObject();
			q2.append("workbeach", pattern);
			BasicDBList values = new BasicDBList();
			values.add(q1);values.add(q2);
			query.append("$or",values);
		}
		int start = (reqData.getPage() - 1) * reqData.getRows();
		BasicDBObject sort = null;
		//设置sort
		if(reqData.getSort()!=null){
			sort = new BasicDBObject(reqData.getSort(), sortmap.get(reqData.getOrder())); 
		}
		long count=super.count("task", query);
		List<DBObject> rows = super.findList("task", query, sort, start, reqData.getRows());
		respData.setRows(rows);
		respData.setTotal(count);
		return respData;
	}
	
	public String addrules(String id,String rid,String taskid){
		if(!StringUtils.hasLength(id))return null;
		
		String pid = "0";
		long cid = 1 ;
		if(!StringUtils.hasLength(taskid)){
			taskid = new ObjectId().toString();
		}else{
			cid = this.count("rule",new BasicDBObject("taskid",taskid))+1;
		}
		if(StringUtils.hasLength(rid)){
			DBObject prule = this.findOne("rule", new BasicDBObject("_id",new ObjectId(rid)));
			if(null==prule)return null;
			pid = prule.get("cid").toString();
		}
		
		String[] ids = id.split(",");
		List<ObjectId> idlist = new ArrayList<ObjectId>();
		for(String str:ids){
			ObjectId objid = new ObjectId(str);
			idlist.add(objid);
		}
		List<DBObject> rules = this.findList("rulebase",new BasicDBObject("_id",new BasicDBObject("$in",idlist)));
		
		if(null==rules||rules.size()==0)return null;
		
		for(int i = 0 ; i < rules.size(); i++){
			BasicDBObject ob = new BasicDBObject();
			ob.append("pid",pid);
			ob.append("cid",(cid+i)+"");
			ob.append("rid", rules.get(i).get("_id").toString());
			ob.append("name",rules.get(i).get("rulename"));
			ob.append("taskid",taskid);
			this.insert("rule",ob);
		}
		return taskid;
	}
	
	public void addTask(Form form){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
		BasicDBObject ob = new BasicDBObject();
		if(StringUtils.hasLength(form.getId())){
			ob.append("_id",new ObjectId(form.getId()));
		}else{
			ob.append("_id",new ObjectId());
		}
		ob.append("note",form.getNote());
		ob.append("url",form.getUrl());
		ob.append("workbeach",form.getWorkbeach());
		ob.append("header",super.deserialize(form.getHeader()));
		ob.append("root",true);
		ob.append("cookie",super.deserialize(form.getCookie()) );
		ob.append("rules",null);
		ob.append("crawlerdate",sdf.format(new Date()));
		ob.append("state","-1");
		ob.append("extedata",super.deserialize(form.getExtedata()));
		this.save("task", ob);
	}
	
	public void updataTask(Form form){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
		BasicDBObject ob = new BasicDBObject();
		ob.append("note",form.getNote());
		ob.append("url",form.getUrl());
		ob.append("workbeach",form.getWorkbeach());
		ob.append("method",form.getMeth());
		ob.append("charset",form.getCharset());
		ob.append("header",super.deserialize(form.getHeader()));
		ob.append("processor", form.getProcessor());
		ob.append("cookie",super.deserialize(form.getCookie()) );
		ob.append("data",super.deserialize(form.getData()));
		ob.append("crawlerdate",sdf.format(new Date()));
		ob.append("extedata",super.deserialize(form.getExtedata()));
		this.updateSingle("task",new BasicDBObject("_id",new ObjectId(form.getId())), ob);
	}
	
	public void getchild(List<DBObject> list){
		if (list != null && list.size()>0) {
			for (DBObject o : list) {
				List<DBObject> child = ruleService.ruletree(o.get("taskid").toString() ,o.get("cid").toString());
				if (!child.isEmpty()) {
					for (int i = 0; i < child.size(); i++) {
						DBObject ruleBase = ruleBaseService.findRuleBase(child.get(i).get("rid").toString());
						DBObject rule = child.get(i);
						rule.putAll(ruleBase);
					}
					o.put("children", child);
					getchild(child);
				}
			}
		}
	}
	
	public List<DBObject> getchild1(List<DBObject> list){
		if (list != null && list.size()>0) {
			for (DBObject o : list) {
				String rid=o.get("rid").toString();
				DBObject ruleBase = ruleBaseService.findRuleBase(rid);
				o.putAll(ruleBase);
				if(o.containsKey("children")){
					o.put("children", getchild1((List<DBObject>)o.get("children")));
				}
			}
		}
		return list;
	}
	
	public void runTask(String ids){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
		if(!StringUtils.hasLength(ids))return;
		String[] id = ids.split(",");
		for(String _id : id){
			this.updateSingle("task",new BasicDBObject("_id",new ObjectId(_id)),new BasicDBObject("state", "0").append("crawlerdate", sdf.format(new Date())));
		}
	}
	
	public DBObject getTaskById(String tid){
		if(!StringUtils.hasLength(tid))return null;
		return this.queryById("task", tid);
	}
	
	public DBObject getTaskByWorkbeach(){
		DBObject query=new BasicDBObject();
		query.put("workbeach", "imp_keyword");
		List<DBObject> tasks= this.findList("task", query);
		return tasks.get(0);
	}
	
	public String insertKWtask(String url,String uid,String charset,DBObject taskDbObject,String type){
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
			taskDbObject.removeField("_id");
			taskDbObject.put("charset",charset);
			taskDbObject.put("url", url);
			BasicDBObject basicDBObject=new BasicDBObject();
			basicDBObject.put("uid",uid);
			basicDBObject.put("type",type);
			taskDbObject.put("uid",uid);
			taskDbObject.put("workbeach","keyword");
			taskDbObject.put("extedata",basicDBObject);
			taskDbObject.put("state", "0");
			taskDbObject.put("crawlerdate", sdf.format(new Date()));
			return this.save("task", taskDbObject);
	}
	
	
	public List<DBObject> getCityList(String type,String key){
		BasicDBObject ob = new BasicDBObject();
		if(StringUtils.hasLength(type)){
			ob.append("type",type);
		}
		if(StringUtils.hasLength(key)){
			Pattern pattern = Pattern.compile("^.*" + key + ".*$", Pattern.CASE_INSENSITIVE);
			BasicDBObject q1 = new BasicDBObject();
			q1.append("province",pattern);
			BasicDBObject q2 = new BasicDBObject();
			q2.append("city",pattern);
			BasicDBList list = new BasicDBList();
			list.add(q1);
			list.add(q2);
			ob.append("$or", list);
		}
		return this.findList("city",ob);
	}
	
	public List<DBObject> getWBList(){
		return this.findList("client",new BasicDBObject());
	}
	
	public Object timerlist(ReqData reqData, String name){
		BasicDBObject query = new BasicDBObject();
		if(StringUtils.hasLength(name)){
			Pattern  pattern = Pattern.compile("^.*" + name + ".*$", Pattern.CASE_INSENSITIVE);
			query.append("name", pattern);
		}
		RespData<List<DBObject>> rows = super.page("timer", query, reqData);
		return  rows;
	}
	
	public void allottask(String tids,String wids){
		if(!StringUtils.hasLength(tids))return;
		if(!StringUtils.hasLength(wids))return;
		String[] tid = tids.split(",");
		String[] wid = wids.split(",");
		List<ObjectId> list = new ArrayList<ObjectId>();
		for(String id:tid){
			list.add(new ObjectId(id));
		}
		this.updateMultiSingle("task",new BasicDBObject("_id",new BasicDBObject("$in",list)),new BasicDBObject("client",wid));
	}
	
	public List<DBObject> getTaskByWork(String workbeach){
		if(!StringUtils.hasLength(workbeach))return null;
		BasicDBObject query = new BasicDBObject();
		query.append("workbeach", workbeach);
		return this.findList("task", query);
	}

	public void clear_ram() {
			super.set_DB("admin");
			super.db.setUsername("admin");
			System.out.println(super.db.getDB().command(new BasicDBObject("closeAllDatabases", 1)));
			super.set_DB("spider");
			super.db.setUsername("spider");
	}
}
